﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Romulus.Nes;

namespace SolKeyTest
{
    public enum GameSprites
    {
        Dana
    }

    public static class SolKeySprites
    {
        private static Dictionary<GameSprites, SpriteDef> Sprites =
            new Dictionary<GameSprites, SpriteDef>();

        /// <summary>
        /// Stores one tile as a sprite
        /// </summary>
        /// <param name="SpriteType"></param>
        /// <param name="TileOffset"></param>
        public static void StoreSpriteDef(GameSprites SpriteType, SpriteTile[] SpriteTiles)
        {
            Sprites.Add(SpriteType, new SpriteDef(SpriteTiles));
        }

        public static SpriteTile TilesToSprites(byte TileIndex)
        {
            SpriteTile sprite = new SpriteTile(TileIndex, 0, 0, Blitter.FlipFlags.None);
            return sprite;
        }

        public static SpriteDef Player { get { return Sprites[GameSprites.Dana]; } }
    }

    public enum GameTiles
    {
        Door,
        Key,
        SolidBlock,
        MagicBlock,
        MagicSeal1,
        MagicSeal2,
        MagicSeal3,
        MagicSeal4,
        SolomonSeal,
        BackgroundTile,
        Bell,
        SmallFlameJar,
        LargeFlameJar,
        SmallJewel,
        LargeJewel,
        BlueDiamond,
        GoldDiamond,
        Scroll,
        SpawnShield,
        SpawnBat,
        Blank,
        FakeDoor,
        FakeOpenDoor,
        FakeOpenDoor2,
        FakeOpenDoor3,
        FakeBrokenBlock,
        HalfLifeJar,
        FullLifeJar,
        HalfHourGlass,
        FullHourGlass,
        YellowJewel_5k,
        Star_10k,
        Star_20k,
        YellowJewel_50k,
        Origami,
        DemonHead,
        Sphinx,
        Helmet,
        Lamp,
        OneUpJar,
        KillJar,
        BlueKey,
        BlueFireExtend,
        Page,
        WarpFlag,
        GraySphere_100,
        GraySphere_200,
        GoldSphere_1k,
        GoldSphere_2k
    }

    public static class SolKeyTiles
    {
        private static void AddItemDefinition(GameTiles TileType, byte Index, byte PatternOffset, byte Palette)
        {
            Tiles.Add(TileType, GetTile_2x2((byte)PatternOffset, (byte)Palette));
            TileIndex.Add((byte)Index, TileType);
        }

        static SolKeyTiles()
        {
            // Load the tiles
            Tiles.Add(GameTiles.BackgroundTile, NewBackground());
            Tiles.Add(GameTiles.Door, GetTile_2x2((byte)0x40, (byte)0x01));
            Tiles.Add(GameTiles.MagicBlock, GetTile_2x2((byte)0x90, (byte)0x01));

            // Assign the indexes
            AddItemDefinition(GameTiles.FakeBrokenBlock, 0x01, 0x94, 0x01);
            AddItemDefinition(GameTiles.FakeDoor, 0x02, 0x40, 0x01);
            AddItemDefinition(GameTiles.SolidBlock, 0x03, 0x84, 0x00);
            AddItemDefinition(GameTiles.SpawnBat, 0x04, 0x3C, 0x00);
            AddItemDefinition(GameTiles.SpawnShield, 0x05, 0x58, 0x01);
            
            // Special for key
            Tiles.Add(GameTiles.Key, GetTile_2x2((byte)0x8D, (byte)0x01, true));
            TileIndex.Add(0x06, GameTiles.Key); // NEVER EVER USE THIS BECAUSE IT SCREWS UP THE GAME
            
            AddItemDefinition(GameTiles.FakeOpenDoor, 0x07, 0x44, 0x01);
            AddItemDefinition(GameTiles.BlueDiamond, 0x08, 0x70, 0x02);
            // 0x09 - 0xb are just states of the blue diamond.  should never appear in the wild.
            
            AddItemDefinition(GameTiles.GoldDiamond, 0x0c, 0x70, 0x01);
            // 0x0d - 0xf are just states of the gold diamond.  should never appear in the wild.
            // 0x10 blank

            //AddItemDefinition(GameTiles.HalfLifeJar, 0x11, 0x40, 0x01);
            AddItemDefinition(GameTiles.FullLifeJar, 0x12, 0x4C, 0x00);
            AddItemDefinition(GameTiles.FullHourGlass, 0x13, 0x78, 0x02);
            AddItemDefinition(GameTiles.HalfHourGlass, 0x14, 0x7C, 0x01);
            AddItemDefinition(GameTiles.SmallFlameJar, 0x15, 0x64, 0x02);
            AddItemDefinition(GameTiles.LargeFlameJar, 0x16, 0x64, 0x01);
            // Special for Scroll
            Tiles.Add(GameTiles.Scroll, GetTile_2x2((byte)0x99, (byte)0x01, true));
            TileIndex.Add(0x17, GameTiles.Scroll);
            
            AddItemDefinition(GameTiles.Bell, 0x18, 0x9C, 0x01);
            AddItemDefinition(GameTiles.KillJar, 0x19, 0x4C, 0x01);
            AddItemDefinition(GameTiles.BlueKey, 0x1a, 0x8C, 0x02);
            AddItemDefinition(GameTiles.BlueFireExtend, 0x1b, 0x6C, 0x02);
            AddItemDefinition(GameTiles.MagicSeal1, 0x1c, 0x50, 0x01);
            AddItemDefinition(GameTiles.MagicSeal2, 0x1d, 0x54, 0x01);
            AddItemDefinition(GameTiles.MagicSeal3, 0x1e, 0x5C, 0x01);
            AddItemDefinition(GameTiles.MagicSeal4, 0x1f, 0x74, 0x01);
            
            AddItemDefinition(GameTiles.SolomonSeal, 0x20, 0x68, 0x00);
            AddItemDefinition(GameTiles.Page, 0x21, 0x88, 0x03); // Page of Space/Time, depends on tile set
            AddItemDefinition(GameTiles.WarpFlag, 0x22, 0xAC, 0x01);
            AddItemDefinition(GameTiles.FakeOpenDoor2, 0x23, 0x44, 0x00);  // BAD if this is touched.  DO NOT USE
            AddItemDefinition(GameTiles.FakeOpenDoor3, 0x24, 0x44, 0x00);  // BAD if this is touched.  DO NOT USE
            AddItemDefinition(GameTiles.GraySphere_100, 0x25, 0x34, 0x00);

            // Special for GoldSphere_200
            TileIndex.Add(0x26, GameTiles.GraySphere_200);
            Tiles.Add(GameTiles.GraySphere_200, GetMultiTile(0x34, 0x80, 0x36, 0x82, 0x00));
            AddItemDefinition(GameTiles.SmallJewel, 0x27, 0x30, 0x02);
            AddItemDefinition(GameTiles.GoldSphere_1k, 0x28, 0x34, 0x03);
            
            // Special for GoldSphere_2k
            TileIndex.Add(0x29, GameTiles.GoldSphere_2k);
            Tiles.Add(GameTiles.GoldSphere_2k, GetMultiTile(0x34, 0x80, 0x36, 0x82, 0x03));

            AddItemDefinition(GameTiles.YellowJewel_5k, 0x2a, 0x30, 0x01);
            AddItemDefinition(GameTiles.Star_10k, 0x2b, 0x38, 0x03);

            // Special for Star_20k
            TileIndex.Add(0x2c, GameTiles.Star_20k);
            Tiles.Add(GameTiles.Star_20k, GetMultiTile(0x38, 0x81, 0x3A, 0x83, 0x03));

            AddItemDefinition(GameTiles.YellowJewel_50k, 0x2d, 0x30, 0x03);
            
            // Special for Origami
            TileIndex.Add(0x2e, GameTiles.Origami);
            Tiles.Add(GameTiles.Origami, GetMultiTile(0xA8, 0xA9, 0x49, 0x4B, 0x03)); // 100k
            // Special for DemonHead
            TileIndex.Add(0x2f, GameTiles.DemonHead);
            Tiles.Add(GameTiles.DemonHead, GetMultiTile(0x20, 0x21, 0x1A, 0x23, 0x01)); // 200k
            
            // Special for Sphinx
            TileIndex.Add(0x30, GameTiles.Sphinx);
            Tiles.Add(GameTiles.Sphinx, GetMultiTile(0x10, 0x13, 0x19, 0x19, 0x01)); // 500k
            AddItemDefinition(GameTiles.Helmet, 0x31, 0x88, 0x01); // 1M
            
            // Special for DemonHead
            TileIndex.Add(0x32, GameTiles.Lamp);
            Tiles.Add(GameTiles.Lamp, GetMultiTile(0x14, 0x1D, 0x1E, 0x1F, 0x03)); // 500k
            AddItemDefinition(GameTiles.OneUpJar, 0x33, 0x60, 0x01);
            // 34-36 are also 1-ups.
        }

        private static Dictionary<GameTiles, TileEntry[,]> Tiles =
            new Dictionary<GameTiles, TileEntry[,]>();

        private static Dictionary<byte, GameTiles> TileIndex =
            new Dictionary<byte, GameTiles>();

        private static TileEntry[,] NewBackground()
        {
            byte Offset = 0x2C;
            byte TilePalette = 0x0;
            TileEntry[,] tEntry = new TileEntry[1, 1];
            tEntry[0, 0] = new TileEntry(Offset, TilePalette);
            return tEntry;
        }

        private static TileEntry[,] GetMultiTile(byte TileOffset1, byte TileOffset2, byte TileOffset3, byte TileOffset4, byte TilePalette)
        {
            TileEntry[,] tEntry = new TileEntry[2, 2];
            tEntry[0, 0] = new TileEntry(TileOffset1, TilePalette);
            tEntry[0, 1] = new TileEntry(TileOffset2, TilePalette);
            tEntry[1, 0] = new TileEntry(TileOffset3, TilePalette);
            tEntry[1, 1] = new TileEntry(TileOffset4, TilePalette);
            return tEntry;
        }

        private static TileEntry[,] GetTile_2x2(byte Offset, byte TilePalette, bool BlankCorner)
        {
            TileEntry[,] tEntry = new TileEntry[2, 2];
            tEntry[0, 0] = new TileEntry(0x2C, TilePalette);
            tEntry[0, 1] = new TileEntry(Offset, TilePalette);
            tEntry[1, 0] = new TileEntry((byte)(Offset + 0x1), TilePalette);
            tEntry[1, 1] = new TileEntry((byte)(Offset + 0x2), TilePalette);
            return tEntry;
        }

        private static TileEntry[,] GetTile_2x2(byte Offset, byte TilePalette)
        {
            TileEntry[,] tEntry = new TileEntry[2, 2];
            tEntry[0, 0] = new TileEntry(Offset, TilePalette);
            tEntry[0, 1] = new TileEntry((byte)(Offset + 0x1), TilePalette);
            tEntry[1, 0] = new TileEntry((byte)(Offset + 0x2), TilePalette);
            tEntry[1, 1] = new TileEntry((byte)(Offset + 0x3), TilePalette);

            return tEntry;
        }
        public static TileEntry[,] Door
        {
            get
            {
                return Tiles[GameTiles.Door];
            }
        }
        public static TileEntry[,] Key
        {
            get { return Tiles[GameTiles.Key]; }
        }
        public static TileEntry[,] MagicSeal_1
        {
            get
            {
                return Tiles[GameTiles.MagicSeal1];
            }
        }
        public static TileEntry[,] EvilMirror
        {
            get
            {
                return GetTile_2x2((byte)0x58, (byte)0x01);
            }
        }
        public static TileEntry[,] MagicBlock
        {
            get
            {
                return Tiles[GameTiles.MagicBlock];
            }
        }
        public static TileEntry[,] SolidBlock
        {
            get
            {
                return Tiles[GameTiles.SolidBlock];
            }
        }
        public static TileEntry[,] SpawnShield
        {
            get
            { return Tiles[GameTiles.SpawnShield]; }
        }
        public static TileEntry[,] BackgroundTile
        {
            get
            {
                return Tiles[GameTiles.BackgroundTile];
            }
        }

        public static TileEntry[,] GetTileByIndex(byte index)
        {
            if (TileIndex.ContainsKey(index))
                return Tiles[TileIndex[index]];
            else return null;
        }
    }
}
